﻿package {
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	import CubeModel;
	import CubeControl;
	import flash.display.DisplayObject;
	import flash.events.EventDispatcher;
	import flash.events.Event;
	
	public class CubeDisplay
	{
		
		public static const DEFAULT_CUBE_SIZE = 50;
		private static const DEFAULT_FACE_COLORS = [0xDCE4D2,0xB8D49A,0x628141,0x335D7E,0x93BEDF,0x325B91];
		private static const DEFAULT_LINE_COLOR = 0x000000;
		
		private var cubeDisplay:Sprite;
		private var cubeModel:CubeModel;
		var displayVertices:Vector.<Point>;
		var faceDistances:Array = [];
		private var lineColor:uint;
		private var lineAlpha:Number;
		private var faceColors:Vector.<uint>;
		private var faceAlpha:Number;
		
		public function CubeDisplay(parentSprite:Sprite, cubeSize:Number = DEFAULT_CUBE_SIZE) {
			
			
			cubeModel = new CubeModel(cubeSize);
			cubeDisplay = new Sprite();
			parentSprite.addChild(cubeDisplay);
			
			// 2D co-ordinates of 3D cube
			displayVertices = new Vector.<Point>();
			
			lineColor = DEFAULT_LINE_COLOR;
			faceColors = new Vector.<uint>;
			for(var i:int = 0; i < CubeModel.NUMBER_OF_FACES; i++) {
				faceColors[i] = DEFAULT_FACE_COLORS[i];
			}
			
			lineAlpha = 1.0;
			faceAlpha = 0.4;
		}
		
		public function rotateAndDrawCube(rotateX:Number, rotateY:Number, rotateZ:Number):void {
			rotateCube(rotateX, rotateY, rotateZ);
			drawCube();
		}
		
		public function drawCube():void {
			cubeDisplay.graphics.clear();
			
			var faces:Vector.<Array> = cubeModel.getFaces();
			
			for (var i:int = 0; i < CubeModel.NUMBER_OF_FACES; i++) // 6
			{
				var currentFace:int = faceDistances[i][1];
				var faceLength:int = faces[currentFace].length;
				
				cubeDisplay.graphics.lineStyle(1, lineColor, lineAlpha);
				cubeDisplay.graphics.beginFill(faceColors[currentFace], faceAlpha);
				cubeDisplay.graphics.moveTo(displayVertices[faces[currentFace][0]].x, displayVertices[faces[currentFace][0]].y);

				// draw the lines 1, 2 and 3
				for (var j:int = 1; j < faceLength; j++) {
					cubeDisplay.graphics.lineTo(displayVertices[faces[currentFace][j]].x,displayVertices[faces[currentFace][j]].y);
				}
				
				// link up to starting point
				cubeDisplay.graphics.lineTo(displayVertices[faces[currentFace][0]].x,displayVertices[faces[currentFace][0]].y);
				cubeDisplay.graphics.endFill();
			}
			
		}
		
		public function rotateCube(rotateX:Number, rotateY:Number, rotateZ:Number):void {
			cubeModel.rotate(rotateX, rotateY, rotateZ);
			var vertices:Vector.<Vector3D> = cubeModel.getVertices();
			var faces:Vector.<Array> = cubeModel.getFaces();

			var zAverage:Number;
			var distance:Number;
			var currentFace:int;
			var faceLength:int
			
			var i:int;
			var j:int;
			for (i = 0; i < CubeModel.NUMBER_OF_FACES; i++) {
				faceLength = faces[i].length;
				zAverage = 0;
				
				for (j = 0; j < faceLength; j++) {
					zAverage +=  vertices[faces[i][j]].z;
				}
				zAverage /=  faceLength;
				
				distance = zAverage;
				faceDistances[i] = [distance, i];
			}

			faceDistances.sort(byDistance);

			for (i = 0; i < CubeModel.NUMBER_OF_VERTICES; i++) {
				displayVertices[i] = new Point();
				displayVertices[i].x = vertices[i].x;
				displayVertices[i].y = vertices[i].y;

			}
			
			// we need to pass the display vertices to the parent class
			// for the MenuItemHandler class so that it can update positions as the cube spins round.
			//(this.parent.parent as InteractiveCube).verticesChanged(vertices);
			
		}
		
		public function reset():void {
			cubeModel.reset();
			rotateAndDrawCube(0.0, 0.0, 0.0);
		}
		
		public function getVerticeAtIndex(index:uint):Vector3D {
			
			return cubeModel.getVerticeAtIndex(index);
		}
		
		public function getVertexDisplayPoint(index:uint):Point {
			return displayVertices[index];
		}
		
		public function setFaceColors(faceColors:Vector.<uint>):void {
			if(faceColors.length == CubeModel.NUMBER_OF_FACES) {
				this.faceColors = faceColors;
			}
		}
		
		public function getFaceColors():Vector.<uint> {
			return faceColors;
		}
		
		public function setFaceAlpha(faceAlpha:Number) {
			if(faceAlpha >= 0.0 && faceAlpha <= 1.0) {
				this.faceAlpha = faceAlpha;
			}
		}
		
		public function getFaceAlpha():Number {
			return faceAlpha;
		}
		
		public function setLineColor(lineColor:uint):void {
			this.lineColor = lineColor;
		}
		
		public function getLineColor():uint {
			return lineColor;
		}
		
		public function setLineAlpha(lineAlpha:Number) {
			if(lineAlpha >= 0.0 && lineAlpha <= 1.0) {
				this.lineAlpha = lineAlpha;
			}
		}
		
		public function getLineAlpha():Number {
			return lineAlpha;
		}
		
		private function byDistance(v:Array,w:Array):Number {
			if (v[0] > w[0]) {
				return -1;
			}
			else if (v[0]<w[0]) {
				return 1;
			}
			else {
				return 0;
			}
		}
	}
	
}